iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0
Software Development

或躍在淵的CAE: 讓咱們用Python會一會ANSA + LS-DYNA系列 第 13

[Day13] - Box Drop Project精進計畫(5) - Plate

  • 分享至 

  • xImage
  •  

今天我們開始來探討,如何能夠有邏輯地來產生nodeelement Entity,而不是每需要一個Entity就直接呼叫一次creator function

今天先改進Plate[Day14]繼續討論如何改進box

核心概念

目前的Plate是由單個QUAD4 element構成。

  • 如果我們從中間劃一刀,是否就能將其變為兩個QUAD4 element呢?
  • 如果再從另一個方向的中間劃一刀,是否就能將其變為四個QUAD4 element呢?
  • 如果...

很多次如果...之後,是不是就可以做出一個網格大小合理的平板了呢?

Plate Grids

有了初步的想法之後,我們來思考一下如何執行? 我們希望能夠寫出一個function,在給定x長度y長度x及y方向各自元素個數後,能回傳所有的座標(我們稱作grid)。

我們的解法是使用numpymeshgrid function來產生(x, y)座標,z座標則由numpyones function產生,我們於其後乘以一個z_elv,用以調整平板的高度(即調整z座標)。

最後,我們還提供了兩個微調的功能,分別是調整旋轉角度及將原點對準某個(x, y)座標(即平移整個平板)。其中旋轉的功能比較難,我們參考了Stack Overflow
的作法,使用了scipy.spatial.transform內的Rotation.from_rotvec function

# gen_seqs.py
from scipy.spatial.transform import Rotation as scipy_rotation


def _gen_one_layer_grids(l, w, en1, en2, *, z_elv=None, move_xy=None, rot_angle=None):
    m1, m2 = en1+1, en2+1
    x = np.linspace(0, l, m1)
    y = np.linspace(0, w, m2)
    X, Y = np.meshgrid(x, y)
    
    x_shape = X.shape
    z_elv = z_elv or 0
    Z = np.ones(x_shape)*z_elv

    if rot_angle is not None:
        XYZ = np.array([X.ravel(), Y.ravel(), Z.ravel()]).transpose()
        r = scipy_rotation.from_rotvec(
            rot_angle*np.array([0, 0, 1]), degrees=True)
        XYZrot = r.apply(XYZ)
        X = XYZrot[:, 0].reshape(x_shape)
        Y = XYZrot[:, 1].reshape(x_shape)
        Z = XYZrot[:, 2].reshape(x_shape)

    if move_xy is not None:
        ox, oy = move_xy
        X += ox
        Y += oy

    yield from (X.flat, Y.flat, Z.flat)

接下來我們用gen_shell_grids來幫_gen_one_layer_grids做一個轉置,這樣就可以得到每一個grid的座標值了。

# gen_seqs.py
def gen_shell_grids(l, w, en1, en2, *, z_elv, move_xy, rot_angle):
    return zip(*_gen_one_layer_grids(l, w, en1, en2,
                                     z_elv=z_elv,
                                     move_xy=move_xy,
                                     rot_angle=rot_angle))

Plate Seqs

Plate Seqs這個部份就需要大家發揮一點想像力。

我們知道LS-DYNA的QUAD4 element是逆時針建立其四個node,所以我們想要達成的是:

  • 能夠沿著x方向,不斷逆時針寫出每個QUAD4 element的四個node id,直到x方向寫到了指定個數。
  • 想像自己的y座標往上走一層,繼續往x方向寫指定個數,直到y方向也寫到指定個數為止。
# gen_seqs.py
def gen_shell_seqs(en1, en2, *, start=1):
    en = en1*en2

    cnt, total_cnt = 0, 0
    while True:
        if total_cnt == en:
            break
        if cnt == en1:
            cnt = 0
        else:
            n1, n2, n3, n4 = start, start+1, start+en1+2, start+en1+1
            total_cnt += 1
            cnt += 1
            yield (n1, n2, n3, n4)
        start += 1

舉例來說,這邊我們想要建立一個x方向有2elementy方向有2elementplate

en1, en2 = 2, 2
list(gen_shell_seqs(en1, en2))

其輸出為:

list(gen_shell_seqs(en1, en2))=[(1, 2, 5, 4), (2, 3, 6, 5), (4, 5, 8, 7), (5, 6, 9, 8)]

plate-nodes

由於gen_shell_seqs是一個generator,所以需要使用list才能print出其內的元素。

Plate Nodes

有了gen_shell_gridsgen_shell_seqs之後,我們可以開始來實作create_plate_nodes function

  • create_plate_nodes先透過gen_shell_grids取得shell_gridsgenerator
  • 透過一個list comprehensions配合create_node及上述generator,產生了node Entities,並收集為一list
  • 呼叫gen_shell_seqs,得到一個generator,作為下一步create_plate_q4shells的準備。
  • 回傳所產生的node Entitiesshell_seqs
# creators.py
def create_plate_nodes(l,
                       w,
                       en1,
                       en2,
                       node_start_id,
                       z_elv=None,
                       move_xy=None,
                       rot_angle=None,
                       deck=None):
    deck = deck or constants.LSDYNA
    shell_grids = gen_shell_grids(
        l, w, en1, en2, z_elv=z_elv, move_xy=move_xy, rot_angle=rot_angle)
    keys = ('NID', 'X', 'Y', 'Z')
    nodes = [create_node(dict(zip(keys, (nid, *xyz))), deck=deck)
             for nid, xyz in enumerate(shell_grids, start=node_start_id)]
    shell_seqs = gen_shell_seqs(en1, en2, start=node_start_id)
    return nodes, shell_seqs

Plate Shells

create_plate_q4shells的寫法與create_plate_nodes差不多。我們透過create_plate_nodes的第二個回傳值shell_seqs配合create_shell來產生QUAD4 Entities,並收集為一list後回傳。

# creators.py
def create_plate_q4shells(shell_seqs, shell_start_id, pid, deck=None):
    deck = deck or constants.LSDYNA
    keys = ('type', 'PID', 'EID', 'N1', 'N2', 'N3', 'N4')
    type_ = ShellType.QUAD
    return [create_shell(dict(zip(keys, (type_, pid, eid, *ns))), deck=deck)
            for eid, ns in enumerate(shell_seqs, start=shell_start_id)]

plate-shells

Code

本日程式碼傳送門


上一篇
[Day12] - Box Drop Project精進計畫(4) - 建立creators
下一篇
[Day14] - Box Drop Project精進計畫(6) - Box
系列文
或躍在淵的CAE: 讓咱們用Python會一會ANSA + LS-DYNA30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言